package com.boot2.core.utils;

import com.boot2.core.exception.BusinessException;
import org.springframework.util.Assert;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.UUID;

/**
* @author zhangweilin
* @date 2018/7/20 9:20
* @description:  随机工具
*/
public final class RandomUtils extends org.apache.commons.lang3.RandomUtils {

	/**
	 * Array of numbers and letters of mixed case. Numbers appear in the list twice
	 * so that there is a more equal chance that a number will be picked. We can use
	 * the array to get a random number or letter by picking a random array index.
	 */

	private static String baseStr = "23456789abcdefghijkmnpqrstuvwxyz23456789ABCDEFGHJKMNPQRSTUVWXYZ";
	private static char[] numbersAndLetters = baseStr.toCharArray();

	/**
	 * 根据指定长度随机生成小写字母
	 * 
	 * @param length
	 *            长度
	 * @return 指定长度的随机小写字母字符串
	 */
	public static String randomLowerWords(int length) {
		/*
		 * 0~9的ASCII为48~57 A~Z的ASCII为65~90 a~z的ASCII为97~122
		 */
		StringBuilder sb = new StringBuilder();
		Random randData = new Random();

		int data = 0;
		for (int i = 0; i < length; i++) {
			data = randData.nextInt(26) + 97;// 保证只会产生97~122之间的整数
			sb.append((char) data);
		}
		return sb.toString();
	}

	/**
	 * 根据指定长度随机生成大写字母
	 * 
	 * @param length
	 *            长度
	 * @return 指定长度的随机大写字母字符串
	 */
	public static String randomUpperWords(int length) {
		/*
		 * 0~9的ASCII为48~57 A~Z的ASCII为65~90 a~z的ASCII为97~122
		 */
		StringBuilder sb = new StringBuilder();
		Random randData = new Random();

		int data = 0;
		for (int i = 0; i < length; i++) {
			data = randData.nextInt(26) + 65;// 保证只会产生97~122之间的整数
			sb.append((char) data);
		}
		return sb.toString();
	}

	/**
	 * 根据指定长度随机生成数字
	 * 
	 * @param length
	 *            长度
	 * @return 指定长度的随机数字
	 */
	public static String randomNumbers(int length) {
		/*
		 * 0~9的ASCII为48~57 A~Z的ASCII为65~90 a~z的ASCII为97~122
		 */
		StringBuilder sb = new StringBuilder();
		Random randData = new Random();

		int data = 0;
		for (int i = 0; i < length; i++) {
			data = randData.nextInt(10);// 仅仅会生成0~9
			sb.append(data);
		}
		return sb.toString();
	}

	/**
	 * 生成32位UUID字符，去除字符'-'
	 * 
	 * @return 32位随机UUID字符串
	 */
	public static String randomCustomUUID() {
		UUID uuid = UUID.randomUUID();
		String uuidStr = uuid.toString();

		return uuidStr.replaceAll("-", "");
	}

	/**
	 * 生成36位UUID字符
	 * 
	 * @return 36未随机UUID字符串
	 */
	public static String randomUUID() {
		return UUID.randomUUID().toString();
	}

	/**
	 * Returns a random String of numbers and letters (lower and upper case) of the
	 * specified length. The method uses the Random class that is built-in to Java
	 * which is suitable for low to medium grade security uses. This means that the
	 * output is only pseudo random, i.e., each number is mathematically generated
	 * so is not truly random.
	 * <p>
	 * <p/>
	 * The specified length must be at least one. If not, the method will return
	 * null.
	 *
	 * @param length
	 *            the desired length of the random String to return.
	 * @return a random String of numbers and letters of the specified length.
	 */
	public static String randomString(int length) {
		if (length < 1) {
			return null;
		}
		// Create a char buffer to put random letters and numbers in.
		char[] randBuffer = new char[length];
		for (int i = 0; i < randBuffer.length; i++) {
			randBuffer[i] = numbersAndLetters[new Random().nextInt(baseStr.length())];
		}
		return new String(randBuffer);
	}

	/**
	 * @description 随机指定范围内N个不重复的数
	 * @param min
	 *            指定范围最小值
	 * @param max
	 *            指定范围最大值
	 * @param n
	 *            随机数个数
	 * @return Integer[]
	 */
	public static Integer[] randomArray(int min, int max, int n) {
		if (n > (max - min + 1)) {
			throw new IllegalArgumentException("随机个数不能大于最大值与最小值的差");
		} else if (max < min) {
			throw new IllegalArgumentException("最大值不能小于最小值");
		}
		Integer[] result = new Integer[n];
		int count = 0;
		while (count < n) {
			Integer num = (int) (Math.random() * (max - min)) + min;
			boolean flag = true;
			for (int j = 0; j < n; j++) {
				if (num.equals(result[j])) {
					flag = false;
					break;
				}
			}
			if (flag) {
				result[count] = num;
				count++;
			}
		}
		return result;
	}

	/**
	 * @description 随机一个整数
	 * @param min
	 *            指定范围最小值
	 * @param max
	 *            指定范围最大值
	 * @return Integer
	 */
	public static Integer randomOne(int min, int max) {
		return randomArray(min, max, 1)[0];
	}

	/**
	 * @description 随机一个整数（含负数）
	 * @param min
	 *            指定范围最小值
	 * @param max
	 *            指定范围最大值
	 * @return Integer
	 */
	public static Integer randomContainMinusOne(int min, int max) {
		int num = randomArray(min, max, 1)[0];
		int num2 = Math.random() >= 0.5 ? 1 : -1;
		return num * num2;
	}

	/**
	 * 生成一个日期范围内的随机时间
	 * @param beginDate
	 * @param endDate
	 * @return
	 */
	public static Date randomDate(String beginDate,String endDate){
		try {
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
			Date start = format.parse(beginDate);
			Date end = format.parse(endDate);
			return randomDateTime(start, end);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException("生成随机日期异常", e);
		}
	}

	/**
	 * 生成一个时间范围内的随机时间
	 * @param beginDate
	 * @param endDate
	 * @return
	 */
	public static Date randomDateTime(String beginDateTime,String endDateTime){
		try {
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			Date start = format.parse(beginDateTime);
			Date end = format.parse(endDateTime);
			return randomDateTime(start, end);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException("生成随机时间异常", e);
		}
	}

	/**
	 * 生成一个时间段内的随机时间点
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static Date randomDateTime(Date startDate, Date endDate) {
		Assert.notNull(startDate,"startDate不能为空" );
		Assert.notNull(endDate,"endDate不能为空" );
		if(startDate.getTime() >= endDate.getTime()){
			return null;
		}
		long date = randomMillisecond(startDate.getTime(),endDate.getTime());
		return new Date(date);
	}

	/**
	 * 在一个毫秒范围内产生一个随机毫秒数
	 * @param begin
	 * @param end
	 * @return
	 */
	public static long randomMillisecond(long begin, long end) {
		long rtn = begin + (long) (Math.random() * (end - begin));
		if (rtn == begin || rtn == end) {
			return randomMillisecond(begin, end);
		}
		return rtn;
	}

}
